﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using FourthWallProject.GameObjects.Solids;
using System.IO;

namespace FourthWallProject.GameObjects.GameComponents
{
    class LevelGrid : Microsoft.Xna.Framework.DrawableGameComponent
    {
        float TileWidth;
        float TileHeight;

        private Game _game;
        public int CurrentLevel;

        public StaticGameTile[,] Grid
        {
            get;
            private set;
        }

        public int GridWidth
        {
            get { return Grid.GetLength(0); }
        }

        public int GridHeight
        {
            get { return Grid.GetLength(1); }
        }

        public LevelGrid(float tileWidth,float tileHeight, Game game)
            : base(game)
        {
            _game = game;
            CurrentLevel = 1;
            TileWidth = tileWidth;
            TileHeight = tileHeight;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="x">x cordinate</param>
        /// <param name="y">y cordiante</param>
        /// <returns></returns>
        /// 
        internal void LoadLevel(int levelNumber)
        {
            CurrentLevel = levelNumber;
            using (Stream fileStream = TitleContainer.OpenStream("Content/Levels/" + levelNumber.ToString() + ".txt"))
            {
                using (StreamReader reader = new StreamReader(fileStream))
                {
                    int width;
                    List<string> lines = new List<string>();

                    string line = reader.ReadLine();
                    width = line.Length;

                    while (line != null)
                    {
                        lines.Add(line);
                        if (line.Length != width)
                            throw new Exception(String.Format("The length of line {0} is different from all preceeding lines.", lines.Count));
                        line = reader.ReadLine();
                    }

                    Grid = new StaticGameTile[width, lines.Count()];

                    for (int y = 0; y < lines.Count(); y++)
                    {
                        for (int x = 0; x < width; x++)
                        {
                            char c = lines[y][x];
                            AddTile(x, y, CreateTile(c, x, y));
                        }
                    }
                }
            }
        }

        private StaticGameTile CreateTile(char p, int x, int y)
        {
            switch (p.ToString().ToUpper())
            {
                case "X":
                    return new StaticGameTile(_game.Content.Load<Texture2D>("Images/Block"), new Rectangle((int)(x * TileWidth), (int)(y * TileHeight), (int)TileWidth, (int)TileHeight), Color.White, SolidState.Solid, _game);
                case "-":
                    return new StaticGameTile(_game.Content.Load<Texture2D>("Images/pinguplattform"), new Rectangle((int)(x * TileWidth), (int)(y * TileHeight), (int)TileWidth, (int)TileHeight), Color.White, SolidState.Solid, _game);
                case "S":
                    GameState.Character.Position = new Vector2(x * TileWidth, y * TileHeight);
                    return null;
                case "E":
                    return new StaticGameTile(_game.Content.Load<Texture2D>("Images/Block"), new Rectangle((int)(x * TileWidth), (int)(y * TileHeight), (int)TileWidth, (int)TileHeight), Color.Brown, SolidState.End, _game);
                case "O":
                    return null;
                default:
                    return null;
            }
        }

        public StaticGameTile GetTile(int x, int y)
        {
            var gridX = (int)Math.Floor(x / TileWidth);
            var gridY = (int)Math.Floor(y / TileWidth);
            if (GridHeight - 1 > gridY && GridWidth - 1 > gridX && gridY > 0 && gridX > 0)
                return Grid[gridX, gridY];
            else
                return null;
        }

        public void AddTile(int x, int y, StaticGameTile Tile)
        {
            if (Tile != null)
            {
                Tile.X = x * TileWidth;
                Tile.Y = y * TileHeight;
                Tile.Width = (int)TileWidth;
                Tile.Height = (int)TileHeight;
                Grid[x, y] = Tile;
            }
        }

        public void RemoveTile(int x, int y)
        {
            Grid[x, y] = null;
        }

        public StaticGameTile CheckCollision(PhysicsEnabledGameObject gameobject)
        {
            //The Char
            var collidedTiles = new List<StaticGameTile>();

            for (int xc = 0; xc < gameobject.Width; xc++)
            {
                for (int yc = 0; yc < gameobject.Height; yc++)
                {
                    var tile = GetTile((int)gameobject.X + xc,(int) gameobject.Y + yc);
                    if (!collidedTiles.Contains(tile) && tile != null)
                        collidedTiles.Add(tile);
                }
            }
            foreach (var tile in collidedTiles)
            {
                if (tile != null)
                {
                    return tile;
                }
            }
            return null;
        }

        public bool CheckCollisionBelow(PhysicsEnabledGameObject gameobject)
        {
            var x = gameobject.Rectangle.X + (gameobject.Rectangle.Width / 2);
            var y = gameobject.Rectangle.Y + gameobject.Rectangle.Height;

            var gridX = (int)Math.Floor(x / TileWidth);
            var gridY = (int)Math.Floor(y / TileWidth);

            if (gridX >= 0 && gridY >= 0 && gridX < GridWidth && gridY < GridHeight)
            {
                if (Grid.GetLength(1) > gridY + 1)
                {
                    if (Grid[gridX, gridY + 1] == null)
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        public override void Draw(GameTime gameTime)
        {
            foreach (var tile in Grid)
            {
                if(tile != null)
                    tile.Draw(gameTime);
            }
        }
    }
}